package com.lkm.app_ui.m.Imple.hsj522;

import android.os.Handler;
import android.os.Looper;

import com.lkm.app_ui.AppConst;
import com.lkm.frame.entity.ResponEntityAbs;
import com.lkm.frame.task.ProgressData;
import com.lkm.frame.task2.Task;
import com.lkm.frame.task2.TaskAdapter;
import com.lkm.hardware_connect.IHardwareControler;
import com.lkm.javatool.CollectionHelp;
import com.lkm.javatool.FlowStepRuner;
import com.lkm.javatool.NumberHelp;
import com.lkm.javatool.lang.RunnablePR;

import java.util.concurrent.atomic.AtomicInteger;



public abstract class AbsCMDSendTask<PR, D> extends TaskAdapter<Object, PR, ResponEntityAbs<D>> {

    private FlowStepRuner mFlowStepRuner;

    private CardCircuitComSe cardCircuitCom;


    private AtomicInteger requestContinueSendCount = new AtomicInteger(0);

    private int tryWriteCount = 0;
    private static final int tryWriteCountMAX = 3;

    private volatile boolean curCmdIsNoResponse = false;



    public AbsCMDSendTask(CardCircuitComSe cardCircuitCom, String id, boolean curCmdIsNoResponse) {
        super(cardCircuitCom.createSerialWriteTaskAutoExecutor(), id, AppConst.getTaskManager2());


        mFlowStepRuner = new FlowStepRuner.Build().addRun(
                "SetWaitResponseRunnable", new SetWaitResponseRunnable())
                .addRun("SentRequestRunnable", new SentRequestRunnable())

                .build();


        this.cardCircuitCom = cardCircuitCom;
        this.curCmdIsNoResponse = curCmdIsNoResponse;

    }

    private volatile Handler writeOutTimeHandler;
    private volatile Handler readOutTimeHandler;




    protected void startWriteOutTimeCountdown() {

        int writeOutTime = configWriteOutTime();
        if (writeOutTime > 0) {

            if (writeOutTimeHandler != null) {
                writeOutTimeHandler.removeCallbacksAndMessages(null);
            }
            writeOutTimeHandler = new Handler(Looper.getMainLooper());
            writeOutTimeHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    complete(new InnerResponEntity().fail(null, "读值失败"));
                }
            }, writeOutTime);
        }
    }



    protected void startReadOutTimeCountdown() {

        int readOutTime = configReadOutTime();
        if (readOutTime > 0) {

            if (readOutTimeHandler != null) {
                readOutTimeHandler.removeCallbacksAndMessages(null);
            }
            readOutTimeHandler = new Handler(Looper.getMainLooper());
            readOutTimeHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    complete(new InnerResponEntity<D>().fail(null, "读值失败"));
                }
            }, readOutTime);
        }
    }



    protected int configWriteOutTime() {
        return 1000 * 10;
    }



    protected int configReadOutTime() {
//		P.p("===="+Config.readOutTime);

        return 1000 * 10;
    }

    @Override
    public void doExecuting(Object param) {
        super.doExecuting(param);
        execSend();
    }

    private void execSend() {
        mFlowStepRuner.resetStep();
        mFlowStepRuner.runNext();
    }



    public void setCurCmdIsNoResponse(boolean is){
        curCmdIsNoResponse = is;
    }



    public void requestContinueSend() {
        requestContinueSendCount.incrementAndGet();
        tryWriteCount = 0;
        execSend();
    }




    private class SentRequestRunnable implements Runnable {
        @Override
        public void run() {

            mTaskExecutor.executorDoAsyncExecuting(new RunnablePR<Object, Void>() {
                @Override
                public Void run(Object p) {

                    CMDWriteData param = createDataEntity(requestContinueSendCount.get());

                    byte[] content = param.getData();
                    byte cmd = param.getCmd();

                    byte[] contentLengths = NumberHelp.intToBytesAsc(content.length); // NumberHelp.intToBytesDesc(content.length);

                    byte SEQNR = 0;
                    byte[] data = CollectionHelp.concatBytes(new byte[]{0x20, SEQNR, cmd, contentLengths[0]}, content, new byte[]{0x00, (byte) 0x03});
                    data[data.length - 2] = HSJ800Help.crc(SEQNR, cmd, content);

                    int writeSize = -1;
                    try {

//                            P.p("===准备发送" + System.currentTimeMillis() + " " + AbsCMDSendTask.this.hashCode() + " " + requestContinueSendCount.get());

                        startWriteOutTimeCountdown();


                        writeSize = ((Task<IHardwareControler, byte[], Void>) cardCircuitCom.getReadTask()).getParam().write(data);


                        if (writeOutTimeHandler != null) {
                            writeOutTimeHandler.removeCallbacksAndMessages(null);
                        }
                        startReadOutTimeCountdown();


//                            String log = "======发送出去了，耗时：" + System.currentTimeMillis() + "  " + writeSize + "字节   " + LogHelp.toString(data).toString();


                    } catch (Exception e) {

                        writeSize = -1;
                    }
                    if (writeSize == -1) {
//                        P.p("==== 发送失败 " + AbsCMDSendTask.this.hashCode());

                        complete(new InnerResponEntity().fail(null, "发送数据失败"));
                    } else {
                        if (curCmdIsNoResponse) {
                            receiveResult(null, requestContinueSendCount.get());
                        }


                    }
                    return null;
                }
            }, getParam());
        }
    }



    private class SetWaitResponseRunnable implements Runnable {
        @Override
        public void run() {

            try {
                Task<IHardwareControler, ReadResponEntity, Void> mReceiveTask = ((Task<IHardwareControler, ReadResponEntity, Void>) cardCircuitCom.getReadTask());
                if (mReceiveTask == null) {
                    complete(new InnerResponEntity().fail(null, "连接已经断开了吧"));
                } else
                    mReceiveTask.addProgresInterceptor(mProgresInterceptor);
            } catch (Exception e) {

            } finally {
                mFlowStepRuner.runNext();
            }
        }
    }




    private ProgresInterceptor<ReadResponEntity> mProgresInterceptor = new ProgresInterceptor<ReadResponEntity>() {
        @Override
        public boolean onInterceptProgresing(Task<?, ReadResponEntity, ?> task, ProgressData<ReadResponEntity> progressData) {
            return false;
        }

        @Override
        public boolean interceptProgressUpdate(Task<?, ReadResponEntity, ?> task, ProgressData<ReadResponEntity> data) {

            if (data.getProgres() == ReadTask.ProgressData_data) {
                if (readOutTimeHandler != null)
                    readOutTimeHandler.removeCallbacksAndMessages(null);
                try {

                    receiveResult(data.getData(), requestContinueSendCount.get());
                } catch (Throwable e) {
                    e.printStackTrace();

                    cancel();

                }
            }

            return false;
        }
    };


    @Override
    public boolean interceptComplete(Task<Object, ?, ResponEntityAbs<D>> task, ResponEntityAbs<D> result) {
        tryWriteCount++;

        if ((result == null || !result.isSuccess()) && getIsContinue() && tryWriteCount < tryWriteCountMAX) {
            execSend();
            return true;
        }

        end();
        return super.interceptComplete(task, result);
    }

    @Override
    public boolean interceptCancel(Task<Object, ?, ResponEntityAbs<D>> task) {
        end();
        return super.interceptCancel(task);
    }

    private void end() {
        try {
            ((Task<IHardwareControler, ReadResponEntity, Void>) cardCircuitCom.getReadTask()).removeProgresInterceptor(mProgresInterceptor);
        } catch (Exception e) {


        }
    }


    @Override
    public void onFinish(ResponEntityAbs<D> r) {
        super.onFinish(r);
        if (writeOutTimeHandler != null)
            writeOutTimeHandler.removeCallbacksAndMessages(null);
        if (readOutTimeHandler != null)
            readOutTimeHandler.removeCallbacksAndMessages(null);
    }

    @Override
    public void onCancel() {
        super.onCancel();
        if (writeOutTimeHandler != null)
            writeOutTimeHandler.removeCallbacksAndMessages(null);
        if (readOutTimeHandler != null)
            readOutTimeHandler.removeCallbacksAndMessages(null);
    }




    protected abstract void receiveResult(ReadResponEntity respon, int requestContinueSendCount);



    protected abstract CMDWriteData createDataEntity(int requestContinueSendCount);


    public CardCircuitComSe getFgdConnectImple() {
        return cardCircuitCom;
    }
}
